#include <WiFi.h>
#include <WiFiClient.h>

// -------------------------- 配置参数 --------------------------
// WiFi配置
const char* ssid = "ZTE";
const char* password = "1233211234567";
const char* serverIP = "192.168.5.39";
const uint16_t serverPort = 1235;

// SPI引脚定义
#define SCLK  18  // 时钟输入
#define MOSI  23  // 主机发送输入
#define MISO  12  // 从机发送输出
#define CS    5   // 片选输入（常低）

// 帧协议（添加帧头和结束标志）
#define SPI_SOF        0xAA  // 帧起始标志
// 结束标志：aabbccddeeffeeddccbbaa（共11字节）
const uint8_t SPI_EOF[] = {0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0xEE, 0xDD, 0xCC, 0xBB, 0xAA};
#define SPI_EOF_LEN    11    // 结束标志长度

// 缓冲区配置（适当增大，确保能容纳数据+帧头+结束标志）
#define TX_FRAME_BUF_SIZE  8192  // 发送帧缓冲（增大到8KB）
#define RX_FRAME_BUF_SIZE  8192  // 接收帧缓冲（增大到8KB）
#define TCP_RECV_BUF_SIZE  5120  // TCP接收临时缓冲

// 超时配置
const unsigned long RECONNECT_DELAY = 2000;  // 重连延迟（ms）
const unsigned long WIFI_TIMEOUT = 10000;    // WiFi超时（ms）
const unsigned long TCP_TIMEOUT = 5000;      // TCP连接超时（ms）

// -------------------------- 全局状态变量 --------------------------
// SPI状态（volatile确保中断安全）
volatile bool csActive = true;               // 片选有效（常低）
volatile uint8_t spiRxByte = 0;              // 接收字节（未处理）
volatile uint8_t spiTxByte = 0;              // 发送字节（当前位）
volatile uint8_t spiBitCount = 0;            // 位计数器（0-7）
volatile bool spiRxReady = false;            // 1字节接收完成标志

// 发送帧缓冲（TCP→SPI）
uint8_t txFrameBuf[TX_FRAME_BUF_SIZE];       // 带帧头和结束标志的完整帧
uint16_t txFrameLen = 0;                     // 帧总长度（含SOF+数据+EOF）
volatile uint16_t txFramePos = 0;            // 当前发送位置（中断用）

// 接收帧缓冲（SPI→TCP）
uint8_t rxFrameBuf[RX_FRAME_BUF_SIZE];       // 有效数据（不含SOF和EOF）
uint16_t rxFrameLen = 0;                     // 有效数据长度
uint8_t rxFrameSync = 0;                     // 帧同步状态（0：未同步，1：同步中）
uint8_t eofMatchCount = 0;                   // EOF标志匹配计数（0~SPI_EOF_LEN）

// 网络状态
WiFiClient client;
enum ConnStatus { DISCONNECTED, CONNECTING_WIFI, CONNECTING_TCP, CONNECTED } connStatus = DISCONNECTED;
unsigned long lastNetOpTime = 0;             // 上次网络操作时间（非阻塞计时）

// WiFi连接分步状态
enum WifiStep { WIFI_STEP_INIT, WIFI_STEP_WAIT } wifiStep = WIFI_STEP_INIT;
// TCP连接分步状态
enum TcpStep { TCP_STEP_INIT, TCP_STEP_WAIT } tcpStep = TCP_STEP_INIT;

// -------------------------- 工具函数：帧处理（带帧头和结束标志） --------------------------
// 添加帧头SOF和结束标志EOF（TCP数据→SPI帧）
void spiFrameData(const uint8_t* inData, uint16_t inLen) {
  txFrameLen = 0;
  // 1. 添加帧起始SOF
  if (txFrameLen < TX_FRAME_BUF_SIZE) {
    txFrameBuf[txFrameLen++] = SPI_SOF;
  }
  // 2. 复制原始数据
  for (uint16_t i = 0; i < inLen && txFrameLen < TX_FRAME_BUF_SIZE; i++) {
    txFrameBuf[txFrameLen++] = inData[i];
  }
  // 3. 添加结束标志EOF（确保缓冲足够）
  for (uint8_t i = 0; i < SPI_EOF_LEN && txFrameLen < TX_FRAME_BUF_SIZE; i++) {
    txFrameBuf[txFrameLen++] = SPI_EOF[i];
  }
  txFramePos = 0;  // 重置发送位置
  Serial.printf("SPI帧准备完成：%u字节（含SOF+数据+EOF）\n", txFrameLen);
  // 打印帧内容（可选，调试用）
  for (int i = 0; i < txFrameLen; ++i) {
    Serial.printf("%02X,",  txFrameBuf[i]);
  }
  Serial.println();
}

// 处理接收字节（SPI→有效数据，检测结束标志）
void spiProcessByte(uint8_t byte) {
  if (byte == SPI_SOF) {
    // 检测到新帧头：重置所有状态，开始新帧
    rxFrameLen = 0;
    rxFrameSync = 1;    // 进入同步状态
    eofMatchCount = 0;  // 重置EOF匹配计数
    Serial.println("检测到SPI帧起始（SOF）");
    return;
  }

  if (rxFrameSync) {  // 同步状态下处理数据
    // 先尝试匹配EOF标志
    if (byte == SPI_EOF[eofMatchCount]) {
      eofMatchCount++;  // 匹配到下一个字节
      // 若完整匹配EOF标志，标记帧结束
      if (eofMatchCount >= SPI_EOF_LEN) {
        rxFrameSync = 0;  // 退出同步状态
        // 有效数据长度 = 总接收长度 - EOF标志长度（因为最后几个字节是EOF）
        rxFrameLen -= (SPI_EOF_LEN - 1);  // 减去已匹配的EOF字节（除了当前这个）
        if (rxFrameLen < 0) rxFrameLen = 0;
        Serial.printf("检测到SPI帧结束（EOF），有效数据：%u字节\n", rxFrameLen);
        return;
      }
    } else {
      // 未匹配到EOF，将之前可能误判为EOF的字节加入数据，并重置匹配计数
      if (eofMatchCount > 0) {
        // 将已匹配的部分（非EOF）加入数据缓冲
        for (uint8_t i = 0; i < eofMatchCount; i++) {
          if (rxFrameLen < RX_FRAME_BUF_SIZE) {
            rxFrameBuf[rxFrameLen++] = SPI_EOF[i];
          } else {
            Serial.println("SPI接收缓冲满，忽略部分数据");
            break;
          }
        }
        eofMatchCount = 0;  // 重置EOF匹配
      }
    }

    // 若未触发EOF结束，将当前字节加入数据（如果不是EOF匹配过程中的字节）
    if (eofMatchCount == 0) {
      if (rxFrameLen < RX_FRAME_BUF_SIZE) {
        rxFrameBuf[rxFrameLen++] = byte;
      } else {
        Serial.println("SPI接收缓冲满，忽略后续数据");
      }
    }
  }
}

// -------------------------- SPI中断服务程序 --------------------------
void IRAM_ATTR sclkISR() {
  // 1. 接收MOSI位（拼接字节）
  bool mosiBit = digitalRead(MOSI);
  spiRxByte = (spiRxByte << 1) | (mosiBit ? 1 : 0);

  // 2. 发送MISO位（从缓冲取数据）
  if (txFramePos < txFrameLen) {
    spiTxByte = txFrameBuf[txFramePos];
    bool misoBit = (spiTxByte >> (7 - spiBitCount)) & 1;
    digitalWrite(MISO, misoBit);
  } else {
    digitalWrite(MISO, LOW);  // 无数据时输出低
  }

  // 3. 完成1字节处理
  if (++spiBitCount >= 8) {
    spiRxReady = true;  // 标记字节就绪（主循环处理）
    if (txFramePos < txFrameLen) txFramePos++;  // 移动发送指针
    // 重置位计数和接收字节
    spiBitCount = 0;
    spiRxByte = 0;
  }
}

// -------------------------- 初始化 --------------------------
void initSpiSlave() {
  // 配置引脚
  pinMode(SCLK, INPUT_PULLDOWN);
  pinMode(MOSI, INPUT_PULLDOWN);
  pinMode(MISO, OUTPUT);
  digitalWrite(MISO, LOW);  // MISO初始低电平

  // 注册SCLK上升沿中断
  attachInterrupt(digitalPinToInterrupt(SCLK), sclkISR, RISING);

  // 初始化缓冲状态
  txFrameLen = 0;
  txFramePos = 0;
  rxFrameLen = 0;
  rxFrameSync = 0;
  eofMatchCount = 0;

  Serial.println("SPI从机（带SOF和EOF标志）初始化完成");
}

// -------------------------- 网络连接：非阻塞实现 --------------------------
// 非阻塞WiFi连接
void processWiFi() {
  switch (wifiStep) {
    case WIFI_STEP_INIT:
      Serial.println("开始连接WiFi...");
      WiFi.disconnect();
      WiFi.begin(ssid, password);
      lastNetOpTime = millis();
      wifiStep = WIFI_STEP_WAIT;
      break;
    case WIFI_STEP_WAIT:
      if (WiFi.status() == WL_CONNECTED) {
        Serial.println("WiFi连接成功");
        initSpiSlave();
        connStatus = CONNECTING_TCP;  // 切换到TCP连接状态
        wifiStep = WIFI_STEP_INIT;    // 重置WiFi步骤
      } else if (millis() - lastNetOpTime > WIFI_TIMEOUT) {
        Serial.println("WiFi连接超时");
        connStatus = DISCONNECTED;    // 回到断开状态
        wifiStep = WIFI_STEP_INIT;    // 重置WiFi步骤
      }
      break;
  }
}

// 非阻塞TCP连接
void processTCP() {
  switch (tcpStep) {
    case TCP_STEP_INIT:
      Serial.printf("连接服务器 %s:%u...\n", serverIP, serverPort);
      client.connect(serverIP, serverPort);  // 非阻塞连接
      lastNetOpTime = millis();
      tcpStep = TCP_STEP_WAIT;
      break;
    case TCP_STEP_WAIT:
      if (client.connected()) {
        Serial.println("TCP服务器连接成功");
        connStatus = CONNECTED;    // 切换到连接状态
        tcpStep = TCP_STEP_INIT;   // 重置TCP步骤
      } else if (millis() - lastNetOpTime > TCP_TIMEOUT) {
        Serial.println("TCP连接超时");
        client.stop();
        connStatus = DISCONNECTED;  // 回到断开状态
        tcpStep = TCP_STEP_INIT;    // 重置TCP步骤
      }
      break;
  }
}

void setup() {
  // 初始化串口
  Serial.begin(115200);
  while (!Serial) delay(10);  // 等待串口就绪

  // 初始化网络状态
  connStatus = DISCONNECTED;
  WiFi.mode(WIFI_STA);  // 仅STA模式
  WiFi.setSleep(false); // 关闭WiFi休眠
}

// -------------------------- 主循环（全非阻塞） --------------------------
void loop() {
  // 1. 网络状态机（非阻塞）
  switch (connStatus) {
    case DISCONNECTED:
      // 延迟重连
      if (millis() - lastNetOpTime > RECONNECT_DELAY) {
        connStatus = CONNECTING_WIFI;
      }
      break;
    case CONNECTING_WIFI:
      processWiFi();
      break;
    case CONNECTING_TCP:
      processTCP();
      break;
    case CONNECTED:
      // 检查TCP连接是否断开
      if (!client.connected()) {
        Serial.println("TCP连接断开");
        client.stop();
        connStatus = DISCONNECTED;
        lastNetOpTime = millis();
        break;
      }

      // 2. TCP→SPI：接收TCP数据并添加帧头和结束标志
      if (client.available()) {
        uint8_t tcpBuf[TCP_RECV_BUF_SIZE];
        uint16_t len = client.read(tcpBuf, TCP_RECV_BUF_SIZE);  // 非阻塞读取
        if (len > 0) {
          Serial.printf("TCP接收：%u字节\n", len);
          spiFrameData(tcpBuf, len);  // 添加SOF和EOF
        }
      }

      // 3. SPI→TCP：转发完整SPI帧（检测到EOF后）到TCP
      if (rxFrameSync == 0 && rxFrameLen > 0) {
        client.write(rxFrameBuf, rxFrameLen);
        Serial.printf("SPI→TCP：转发%u字节\n", rxFrameLen);
        rxFrameLen = 0;  // 重置接收缓冲
      }
      break;
  }

  // 4. 处理SPI接收的字节（主循环执行，避免中断阻塞）
  if (spiRxReady) {
    noInterrupts();  // 安全拷贝数据
    uint8_t rxByte = spiRxByte;
    spiRxReady = false;
    interrupts();
    // Serial.printf("0x%02X\r\n",rxByte);
    spiProcessByte(rxByte);  // 处理接收字节（检测EOF）
  }

  delay(1);  // 极短延迟，确保高频执行
}